
#include "MyScanner.h"
#include <iostream>
#include <assert.h>
#include <sstream>

MyScanner* MyScanner::_myScanner=NULL;

MyScanner::MyScanner(void){
}

MyScanner::~MyScanner(void){
}

MyScanner* MyScanner::getInstance(){

	if(_myScanner==NULL){
		_myScanner=new MyScanner();
	}
	return _myScanner;

}

string MyScanner::isLexical(string context,int size){
	
	assert(!context.empty());

	_tokens=new queue<MyWord*>();
	string upper_context=toUpperCase(context);
	_size=size;
	_result="TRUE";

	for(int i=0;i<upper_context.length();i++){
		if(_result!="TRUE")
			break;
		//如果是space，則跳過
		if(upper_context.substr(i,1)==" ")
			continue;
		//for(int j=1;j<=context.length()-i;j++){
		for(int j=upper_context.length()-i;j>0;j--){
			string token=upper_context.substr(i,j);
			if(_result!="TRUE")
				break;
			if(patternCheck(token)){
				i+=j-1;
				break;
			}
			if(token.length()==1){
				string temp;
				ostringstream oss(temp);
				oss<<i+1;
				_result=context.substr(i,j)+"(pos "+oss.str()+") is illegal";
				return _result;
			}
		}
	}

	return _result;
}

queue<MyWord*>* MyScanner::getTokens(){
	
	assert(!_tokens->empty());

	return _tokens;
}

bool MyScanner::patternCheck(string token){
	
	assert(!token.empty());
	
	if(_result!="TRUE")
		return false;
	if(normalCheck(token))
		return true;
	if(regexCheck(token))
		return true;
	return false;
}

bool MyScanner::normalCheck(string token){
	
	if(_result!="TRUE")
		return false;

	string words[]={"(",")",",","+","-","*","/"};
	int	wordNumber=7;
	
	//處理words
	for(int i=0;i<wordNumber;i++){
		if(words[i]==token){
			_tokens->push(new MyWord(token));
			return true;
		}
	}
	//處理ariths
	for(int i=0;i<MyWord::arithNumber;i++){
		if(MyWord::ariths[i]==token){
			_tokens->push(new MyWord("arith",token));
			return true;
		}
	}
	return false;
}

bool MyScanner::regexCheck(string token){
	
	if(_result!="TRUE")
		return false;

	if(idCheck(token)){
		_tokens->push(new MyWord("id",token));
		return true;
	}
	if(doubleCheck(token)){
		_tokens->push(new MyWord("double",token));
		return true;
	}
	if(intCheck(token)){
		_tokens->push(new MyWord("int",token));
		return true;
	}
	return false;
}

bool MyScanner::idCheck(string token){

	if(_result!="TRUE")
		return false;

	//第一個位置必須是$
	if(token[0]!='$')
		return false;
	if(token.length()==1)
		_result="$'s next token must be digit";
	//從第二個位置並判斷是否是一個整數
	string intString=token.substr(1,token.length()-1);
	if(intCheck(intString)){
		int number;
		istringstream(intString)>>number;
		if(number>=_size&&_size!=-1){
			_result=token+" is out of bound";
			return false;
		}
		return true;
	}
	if(token.length()==2)
		_result="$'s next token must be digit";
	return false;

}

bool MyScanner::intCheck(string token){
	
	if(_result!="TRUE")
		return false;

	int check_ascii;

	//不容許出現01、001...
	if(token[0]=='0'){
		if(token.length()==1){
			return true;
		}
		else{
			return false;
		}
	}
	check_ascii=token[0];
	//第一個如果不是1~9
	if(check_ascii<49||check_ascii>57){
		return false;
	}
	//是1~9且又剛好只有這個數字則符合
	else{
		if(token.length()==1){
			return true;
		}
	}

	//上面判斷完之後第一個數字必定是1~9，之後的數字則沒有限制
	//可以是0~9
	for(int i=1;i<token.length();i++){
		check_ascii=token[i];
		if(check_ascii<48||check_ascii>57)
			break;
		if(i==token.length()-1){
			return true;
		}
	}
	return false;
}

bool MyScanner::doubleCheck(string token){
	
	if(_result!="TRUE")
		return false;

	int dot;
	//如果字串中找得到小數點表示有可能是double，並記錄這個小數點的位置
	if(token.find('.')!=string::npos){
		dot=token.find('.');
	}
	else
		return false;
	string underZero;
	//確定小數點之後至少有一個數字
	if(dot<token.length()-1){
		underZero=token.substr(dot+1,token.length()-dot-1);
	}
	//小數點前面的必須是整數
	string intString=token.substr(0,dot);
	if(intString.empty()){
		return false;
	}
	if(intCheck(intString)){
		//小數點後面的必須符合下面的規則
		if(underZero.empty()){
			_result=token+" is not float or double";
			return false;
		}
		for(int i=0;i<underZero.length();i++){
			int check_ascii=underZero[i];
			if(check_ascii<48||check_ascii>57)
				break;
			if(i==underZero.length()-1)
				return true;
		}
	}
	return false;

}

string MyScanner::toLowerCase(string token){
	
	assert(!token.empty());

	for(unsigned int i=0;i<token.length();i++){
		token[i]=tolower(token[i]);
	}
	return token;

}

string MyScanner::toUpperCase(string token){
	
	assert(!token.empty());

	for(unsigned int i=0;i<token.length();i++){
		token[i]=toupper(token[i]);
	}
	return token;

}